/*
 * Tezad - Classic puzzle game
 * Copyright 2009 Shayne Riley and Paul Maseberg
 *
 * Tezad is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tezad is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Tezad.  If not, see <http://www.gnu.org/licenses/>
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * To contact the authors on questions or issues regarding the license,
 * you may send an email to <pezads at gmail dot com>
 */

#include "GameCore.h"
#include "ClientGameCore.h"
#include "Command.h"
#include "InputReqs.h"
#include "GraphicsWell.h"
#include "GameWell.h"
#include "NetworkCommandProducer.h"

#include <SDL/SDL_image.h>
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <iostream>


int main(int argc, char **argv)
{

    // Initialize SDL video subsystem, which also inits other important systems.
    if (SDL_Init(SDL_INIT_VIDEO) != 0)
    {
        std::cerr << "SDL_Init Failed: " << SDL_GetError() << std::endl;
        return false;
    }

    // Set the window caption and icon.
    SDL_WM_SetCaption("Tezad", '\0');

    // Create the window with OpenGL.
    SDL_Surface *screen = SDL_SetVideoMode(480, 480, 32, SDL_OPENGL);
    if (screen == NULL)
    {
        std::cerr << "Could not create OpenGL window: " << SDL_GetError() << std::endl;
        SDL_Quit();
        return false;
    }
    glViewport(0, 0, (GLsizei) 480, (GLsizei) 480);

    // We want to make the projection orthogonal.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    // There will be no foreshortening. Objects will be the same size at any
    // distance. The depth-clipping occurs at -1.0 to 1.0.
    gluOrtho2D(0, 30, 0, 30); // lower-left is 0, 0. Upper-right is 640, 480

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0f, 0.0f, 0.0f);

    GameCore* gc = new GameCore();
    GraphicsWell well(gc, 5, 5, 20, 10);


    NetworkCommandProducer ncp;
    gc->attach(makeFunctor((Functor1<Command&> *)0, ncp, &NetworkCommandProducer::update));

    GameCore* gc2 = new GameCore();
//    GraphicsWell well2(gc2, 16, 5, 12, 6);
//    gc2->initializeGame(6, 12, 2, 10, 2, 0); // Small well.
    GraphicsWell well2(gc2, 16, 5, 20, 10);
    gc2->initializeGame(20, 42, 2, 40, 9, 0); // Large well.

    // This is an example of what a ClientGameCore does: Forwarding commands.
    ClientGameCore* cgc = new ClientGameCore();
    gc->attach(makeFunctor((Functor1<Command&> *)0, *cgc, &ClientGameCore::inputCommand));
    GraphicsWell cWell(cgc, 1, 1, 5, 3);


    // resize screen code
    SDL_Event event; //Events
    bool done = false;

    Uint32 startTicks = SDL_GetTicks();
    const Uint32 timeStepTicks = 1000 / 60; // over 60 steps a second.

    while(!done)
    { //While program isn't done

        Uint32 currentTicks = SDL_GetTicks();
        Uint32 diffTicks = currentTicks - startTicks;
        while (diffTicks >= timeStepTicks)
        {
            gc->advanceTimeStep();
            gc2->advanceTimeStep();
            diffTicks -= timeStepTicks;
        }
        startTicks = currentTicks - diffTicks;


        well.drawWell();
        well2.drawWell();
        cWell.drawWell();
        SDL_GL_SwapBuffers();
        while (SDL_PollEvent(&event))
        { //Poll events

            switch (event.type)
            { //Check event type
                case SDL_QUIT: //User hit the X (or equivelent)
                    done = true; //Make the loop end
                    break; //We handled the event
                case SDL_KEYDOWN:
                    if (event.key.keysym.sym == SDLK_UP)
                        gc->inputReqRotateCW();
                    else if (event.key.keysym.sym == SDLK_DOWN)
                        gc->inputReqSoftDown(true);
                    else if (event.key.keysym.sym == SDLK_LEFT)
                        gc->inputReqShiftLeft(true);
                    else if (event.key.keysym.sym == SDLK_RIGHT)
                        gc->inputReqShiftRight(true);
                    else if (event.key.keysym.sym == SDLK_SPACE ||
                            event.key.keysym.sym == SDLK_KP0)
                        gc->inputReqHardDown();
                    else if (event.key.keysym.sym == SDLK_RCTRL)
                        gc->inputReqRotateCCW();
                    else if (event.key.keysym.sym == SDLK_w)
                        gc2->inputReqRotateCW();
                    else if (event.key.keysym.sym == SDLK_s)
                        gc2->inputReqSoftDown(true);
                    else if (event.key.keysym.sym == SDLK_a)
                        gc2->inputReqShiftLeft(true);
                    else if (event.key.keysym.sym == SDLK_d)
                        gc2->inputReqShiftRight(true);
                    else if (event.key.keysym.sym == SDLK_f)
                        gc2->inputReqHardDown();
                    else if (event.key.keysym.sym == SDLK_e)
                        gc2->inputReqRotateCCW();
                break;
                case SDL_KEYUP:
                    if (event.key.keysym.sym == SDLK_DOWN)
                        gc->inputReqSoftDown(false);
                    else if (event.key.keysym.sym == SDLK_LEFT)
                        gc->inputReqShiftLeft(false);
                    else if (event.key.keysym.sym == SDLK_RIGHT)
                        gc->inputReqShiftRight(false);
                    else if (event.key.keysym.sym == SDLK_s)
                        gc2->inputReqSoftDown(false);
                    else if (event.key.keysym.sym == SDLK_a)
                        gc2->inputReqShiftLeft(false);
                    else if (event.key.keysym.sym == SDLK_d)
                        gc2->inputReqShiftRight(false);
            } //Finished with current event
        } //Done with all events for now
    } //Program done, exited

    delete gc;
    delete gc2;
    delete cgc;
}
